package jnpf.util;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import jnpf.database.model.superQuery.SuperJsonModel;
import jnpf.database.model.superQuery.SuperQueryJsonModel;
import jnpf.emnus.SearchMethodEnum;
import jnpf.model.QueryModel;
import jnpf.model.visualJson.FieLdsModel;
import jnpf.model.visualJson.config.ConfigModel;
import jnpf.util.visiual.JnpfKeyConsts;
import lombok.Data;

import java.lang.reflect.Field;
import java.util.*;

@Data
public class QueryUtil {

    /**
     * 运算符
     */
    private SearchMethodEnum symbol;
    /**
     * 逻辑拼接符号
     */
    private boolean and;
    /**
     * 组件标识
     */
    private String jnpfKey;
    /**
     * 字段key
     */
    private String vModel;
    /**
     * 自定义的值
     */
    private Object fieldValue;
    /**
     * 自定义的值2
     */
    private Object fieldValueTwo;

    /**
     * 数据库类型
     */
    private String dbType;

    private List<String> dataList = new ArrayList<>();

    //搜索逻辑
    public <T> QueryWrapper<T> queryList(QueryModel queryModel) {
        QueryWrapper<T> queryWrapper = queryModel.getObj();
        Class entity = queryModel.getEntity();
        dbType = queryModel.getDbType();
        String queryJson = queryModel.getQueryJson();
        List<SuperJsonModel> superJsonModelList = JsonUtil.getJsonToList(queryJson, SuperJsonModel.class);
        for (SuperJsonModel superJsonModel : superJsonModelList) {
            String matchLogic = superJsonModel.getMatchLogic();
            Boolean authorizeLogic = superJsonModel.getAuthorizeLogic();
            boolean isAddMatchLogic = SearchMethodEnum.And.getSymbol().equalsIgnoreCase(matchLogic);
            List<SuperQueryJsonModel> conditionList = superJsonModel.getConditionList();
            if (conditionList.size() == 0) continue;
            queryWrapper.and(gw -> {
                if (authorizeLogic) {
                    gw.and(tw -> {
                        queryWrapperList(entity, tw, conditionList, isAddMatchLogic);
                    });
                } else {
                    gw.or(tw -> {
                        queryWrapperList(entity, tw, conditionList, isAddMatchLogic);
                    });
                }
            });
        }
        return queryWrapper;
    }

    private <T> void queryWrapperList(Class entity, QueryWrapper<T> tw, List<SuperQueryJsonModel> conditionList, boolean isAddMatchLogic) {
        for (SuperQueryJsonModel superQueryJsonModel : conditionList) {
            String logic = superQueryJsonModel.getLogic();
            and = SearchMethodEnum.And.getSymbol().equalsIgnoreCase(logic);
            List<FieLdsModel> queryList = superQueryJsonModel.getGroups();
            queryWrapper(entity, tw, queryList, isAddMatchLogic);
        }
    }

    private <T> void queryWrapper(Class entity, QueryWrapper<T> tw, List<FieLdsModel> queryListAll, boolean isAnd) {
        if (isAnd) {
            tw.and(qw -> {
                query(entity, qw, queryListAll);
            });
        } else {
            tw.or(qw -> {
                query(entity, qw, queryListAll);
            });
        }
    }

    private <T> void query(Class entity, QueryWrapper<T> qw, List<FieLdsModel> queryListAll) {
        for (FieLdsModel fieLdsModel : queryListAll) {
            List<FieLdsModel> queryList = new ArrayList() {{
                add(fieLdsModel);
            }};
            if (and) {
                qw.and(ew -> {
                    fieldsModel(ew, queryList, entity);
                });
            } else {
                qw.or(ew -> {
                    fieldsModel(ew, queryList, entity);
                });
            }
        }
    }

    private void fieldsModel(QueryWrapper wrapper, List<FieLdsModel> queryList, Class entity) {
        for (FieLdsModel fieLdsModel : queryList) {
            ConfigModel config = fieLdsModel.getConfig();
            jnpfKey = config.getJnpfKey();
            symbol = SearchMethodEnum.getSearchMethod(fieLdsModel.getSymbol());
            vModel = fieLdsModel.getVModel();
            if (!and) {
                wrapper.or();
            }
            try {
                Field declaredField = entity.getDeclaredField(vModel);
                declaredField.setAccessible(true);
                vModel = declaredField.getAnnotation(TableField.class).value();
            } catch (Exception e) {

            }
            fieldValue = fieLdsModel.getFieldValueOne();
            fieldValueTwo = fieLdsModel.getFieldValueTwo();
            dataList = fieLdsModel.getDataList();
            if(JnpfKeyConsts.DateSelect.contains(fieLdsModel.getConfig().getJnpfKey())){
                if(ObjectUtils.isNotEmpty(fieLdsModel.getFieldValueOne())){
                    fieldValue = new Date(Long.valueOf(fieLdsModel.getFieldValueOne().toString()));
                }
                if(ObjectUtils.isNotEmpty(fieLdsModel.getFieldValueTwo())){
                    fieldValueTwo = new Date(Long.valueOf(fieLdsModel.getFieldValueTwo().toString()));
                }
            }
            getSymbolWrapper(wrapper);
        }
    }

    private void getNullWrapper(QueryWrapper<?> wrapper) {
        if (!and) {
            wrapper.or(t -> t.isNull(vModel));
        } else {
            wrapper.and(t -> t.isNull(vModel));
        }
    }

    private void getNotNullWrapper(QueryWrapper<?> wrapper) {
        if (!and) {
            wrapper.or(t -> t.isNotNull(vModel));
        } else {
            wrapper.and(t -> t.isNotNull(vModel));
        }
    }

    private void getInWrapper(QueryWrapper<?> wrapper) {
        if (!and) {
            wrapper.or(qw -> {
                for (String id : dataList) {
                    switch (symbol) {
                        case Included:
                            qw.or().like(vModel, id);
                            break;
                        default:
                            qw.notLike(vModel, id);
                            break;
                    }
                }
            });
        } else {
            wrapper.and(qw -> {
                for (String id : dataList) {
                    switch (symbol) {
                        case Included:
                            qw.or().like(vModel, id);
                            break;
                        default:
                            qw.notLike(vModel, id);
                            break;
                    }
                }
            });
        }
    }

    private void getSymbolWrapper(QueryWrapper<?> wrapper) {
        switch (symbol) {
            case IsNull:
                getNullWrapper(wrapper);
                break;
            case IsNotNull:
                getNotNullWrapper(wrapper);
                break;
            case Equal:
                wrapper.eq(vModel, fieldValue);
                break;
            case NotEqual:
                wrapper.ne(vModel, fieldValue);
                break;
            case GreaterThan:
                wrapper.gt(vModel, fieldValue);
                break;
            case LessThan:
                wrapper.lt(vModel, fieldValue);
                break;
            case GreaterThanOrEqual:
                wrapper.ge(vModel, fieldValue);
                break;
            case LessThanOrEqual:
                wrapper.le(vModel, fieldValue);
                break;
            case Like:
                wrapper.like(vModel, fieldValue);
                break;
            case NotLike:
                wrapper.notLike(vModel, fieldValue);
                break;
            case Included:
            case NotIncluded:
                getInWrapper(wrapper);
                break;
            case Between:
                wrapper.between(vModel, fieldValue, fieldValueTwo);
                break;
            default:
                break;
        }
    }
}
